package com.shanjupay.transaction.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shanjupay.common.cache.Cache;
import com.shanjupay.common.domain.BusinessException;
import com.shanjupay.common.domain.CommonErrorCode;
import com.shanjupay.common.util.RedisUtil;
import com.shanjupay.transaction.api.PayChannelService;
import com.shanjupay.transaction.api.dto.PayChannelDTO;
import com.shanjupay.transaction.api.dto.PayChannelParamDTO;
import com.shanjupay.transaction.api.dto.PlatformChannelDTO;
import com.shanjupay.transaction.convert.PayChannelParamConvert;
import com.shanjupay.transaction.convert.PlatformChannelConvert;
import com.shanjupay.transaction.entity.AppPlatformChannel;
import com.shanjupay.transaction.entity.PayChannelParam;
import com.shanjupay.transaction.entity.PlatformChannel;
import com.shanjupay.transaction.mapper.AppPlatformChannelMapper;
import com.shanjupay.transaction.mapper.PayChannelParamMapper;
import com.shanjupay.transaction.mapper.PlatformChannelMapper;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

/**
 * @author whb
 * @create 2021-12-06 12:57
 * @desciption 支付渠道服务 管理平台支付渠道，原始支付渠道，以及相关配置的Service接口实现类
 */
@Service
public class PayChannelServiceImpl implements PayChannelService {
    @Autowired
    private PlatformChannelMapper platformChannelMapper;
    @Autowired
    private AppPlatformChannelMapper appPlatformChannelMapper;
    @Autowired
    private PayChannelParamMapper payChannelParamMapper;
    @Autowired
    private Cache cache;

    /**
     * 查询平台的服务类型
     * @return 平台服务类型集合
     * @throws BusinessException
     */
    @Override
    public List<PlatformChannelDTO> queryPlatformChannelList() throws BusinessException {
        List<PlatformChannel> platformChannels = platformChannelMapper.selectList(null);//查询平台服务类型
        return PlatformChannelConvert.INSTANCE.listentity2listdto(platformChannels);
    }

    /**
     * 为指定应用绑定一个服务类型
     * @param appId 应用id
     * @param platformChannelCodes 服务类型的code
     * @throws BusinessException
     */
    @Override
    public void bindPlatformChannelForApp(String appId, String platformChannelCodes) throws BusinessException {
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>().eq(AppPlatformChannel::getAppId, appId)
                .eq(AppPlatformChannel::getPlatformChannel, platformChannelCodes));//根据应用id和服务类型code查询 ，如果已经绑定则不再插入，否则插入记录
        if (appPlatformChannel==null){
            AppPlatformChannel insertAppPlatformChannel = new AppPlatformChannel();
            insertAppPlatformChannel.setAppId(appId);//设置app应用id
            insertAppPlatformChannel.setPlatformChannel(platformChannelCodes);//设置服务类型编码
            appPlatformChannelMapper.insert(insertAppPlatformChannel);//向表app_platform_channel插入，给指定的服务app绑定平台服务类型
        }else {
            throw new BusinessException(CommonErrorCode.E_300010);
        }
    }

    /**
     * 查询应用app绑定指定平台服务类型的状态
     * @param appId app应用id
     * @param platformChannelCodes 平台服务类型code
     * @return
     */
    @Override
    public int queryAppBindPlatformChannel(String appId, String platformChannelCodes) throws BusinessException {
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>().eq(AppPlatformChannel::getAppId, appId)
                .eq(AppPlatformChannel::getPlatformChannel, platformChannelCodes));//根据应用id和服务类型code查询 ，如果已经绑定则不再插入，否则插入记录
        if (appPlatformChannel!=null){//应用app已经绑定该平台服务类型
            return 1;
        }
        return 0;
    }

    /**
     * 根据平台服务类型查询第三方支付渠道
     * @param platformChannelCode 平台服务类型编码
     * @return 第三方支付渠道列表
     * @throws BusinessException
     */
    @Override
    public List<PayChannelDTO> queryPayChannelByPlatformChannel(String platformChannelCode) throws BusinessException {
        return platformChannelMapper.selectPayChannelByPlatformChannel(platformChannelCode);
    }

    /**
     * 支付渠道参数配置
     * @param payChannelParam 支付渠道参数：商户id、应用id，服务类型code，支付渠道code，配置名称，配置参数(json)
     * @throws BusinessException
     */
    @Override
    public void savePayChannelParam(PayChannelParamDTO payChannelParam) throws BusinessException {
        if (payChannelParam==null || StringUtils.isBlank(payChannelParam.getChannelName()) || StringUtils.isBlank(payChannelParam.getParam())
                || StringUtils.isBlank(payChannelParam.getAppId()) || StringUtils.isBlank(payChannelParam.getPlatformChannelCode())
                || StringUtils.isBlank(payChannelParam.getPayChannel())){
            throw new BusinessException(CommonErrorCode.E_300009);
        }

        //查询app应用和平台服务类型关系id
        Long appPlatformChannelId = selectIdByAppPlatformChannel(payChannelParam.getAppId(),payChannelParam.getPlatformChannelCode());
        if (appPlatformChannelId==null){//app应用未绑定该平台服务类型，不可进行支付渠道参数配置
            throw new BusinessException(CommonErrorCode.E_300011);
        }

        //根据app应用appid与平台服务类型code的关系绑定id和支付渠道code查询PayChannelParam的一条记录
        PayChannelParam entity = payChannelParamMapper.selectOne(new LambdaQueryWrapper<PayChannelParam>().eq(PayChannelParam::getAppPlatformChannelId, appPlatformChannelId)
                .eq(PayChannelParam::getPayChannel, payChannelParam.getPayChannel()));

        if (entity!=null){//如果渠道参数配置已存在，则更新
            entity.setChannelName(payChannelParam.getChannelName());//更新配置名称
            entity.setParam(payChannelParam.getParam());//更新第三方支付渠道的参数，json格式
            payChannelParamMapper.updateById(entity);//更新第三方渠道支付参数
        }else {//如果渠道参数配置不存在，则添加参数配置
            PayChannelParam entityInsert = PayChannelParamConvert.INSTANCE.dto2entity(payChannelParam);
            entityInsert.setId(null);//id由mybatis-plus的主键生成策略自动生成（使用雪花算法）
            entityInsert.setAppPlatformChannelId(appPlatformChannelId);
            payChannelParamMapper.insert(entityInsert);
        }

        //支付渠道参数保存到redis缓存
        savePayParamToRedis(payChannelParam.getAppId(),payChannelParam.getPlatformChannelCode());
    }

    /**
     * 根据应用和服务类型查询支付渠道参数列表
     * @param appId 应用id
     * @param platformChannel 服务类型code
     * @return
     */
    @Override
    public List<PayChannelParamDTO> queryPayChannelParamByAppAndPlatform(String appId, String platformChannel) {
        //cache.setMy("1:2:stringValue", "bbb");
        //查询redis缓存是否存在对应的key
        String redisKey = RedisUtil.keyBuilder(appId, platformChannel);
        Boolean exists = cache.exists(redisKey);

        //redis缓存中存在对应key，读取出值转换成DTO返回
        if (exists){
            String payChannelParamDTO_json = cache.get(redisKey);//从redis读取支付渠道参数列表（json格式）
            return JSON.parseArray(payChannelParamDTO_json, PayChannelParamDTO.class);
        }

        //查出应用appId和服务类型代码在app_platform_channel主键
        Long appPlatformChannelId = selectIdByAppPlatformChannel(appId, platformChannel);
        if (appPlatformChannelId==null){//app应用未绑定平台服务类型
            return null;
        }
        List<PayChannelParam> payChannelParamList = payChannelParamMapper.selectList(new LambdaQueryWrapper<PayChannelParam>().eq(PayChannelParam::getAppPlatformChannelId, appPlatformChannelId));

        //如果redis中没有对应key，则将支付渠道参数列表保存到redis缓存
        savePayParamToRedis(appId, platformChannel);

        return PayChannelParamConvert.INSTANCE.listentity2listdto(payChannelParamList);
    }

    /**
     * 根据应用、服务类型和支付渠道的代码查询该支付渠道的参数配置信息
     * @param appId 应用id
     * @param platformChannel 服务类型code
     * @param payChannel  支付渠道代码
     * @return
     */
    @Override
    public PayChannelParamDTO queryParamByAppPlatformAndPayChannel(String appId, String platformChannel, String payChannel) {
        List<PayChannelParamDTO> payChannelParamDTOList = queryPayChannelParamByAppAndPlatform(appId, platformChannel);//查询app应用绑定的平台服务类型下的第三方支付渠道的参数集合
        for (PayChannelParamDTO payChannelParamDTO:payChannelParamDTOList){
            if (payChannelParamDTO.getPayChannel().equals(payChannel)){//集合中第三方支付渠道code等于参数与的渠道code
                return payChannelParamDTO;
            }
        }
        return null;
    }

    /**
     * 根据平台应用appid、平台服务类型code查询应用和平台服务关系
     * @param appId app应用appid
     * @param platformChannelCode 平台服务类型code
     * @return
     */
    private Long selectIdByAppPlatformChannel(String appId, String platformChannelCode) {
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>().eq(AppPlatformChannel::getAppId, appId)
                .eq(AppPlatformChannel::getPlatformChannel, platformChannelCode));

        if (appPlatformChannel!=null){
            return appPlatformChannel.getId();//返回app应用与服务类型关系绑定的id
        }
        return null;
    }

    /**
     * 根据app应用的appid和平台服务类型将查询到支付渠道参数配置列表写入redis
     * @param appId app应用appid
     * @param platformChannelCode 平台服务类型code
     */
    private void savePayParamToRedis(String appId, String platformChannelCode) {
        //得到redis中key(支付渠道参数配置列表的key)
        //redis中key格式：SJ_PAY_PARAM:应用id:服务类型code，例如：SJ_PAY_PARAM：ebcecedd-3032-49a6-9691-4770e66577af：shanju_c2b
        String redisKey = RedisUtil.keyBuilder(appId, platformChannelCode);

        Boolean exists = cache.exists(redisKey);//查询redis中是否存在key
        if (exists){
            cache.del(redisKey);//redis存在key，则删除
        }

        Long appPlatformChannelId = selectIdByAppPlatformChannel(appId, platformChannelCode);//查询app应用和平台服务类型的关系id
        if (appPlatformChannelId!=null){
            List<PayChannelParam> payChannelParamList = payChannelParamMapper.selectList(new LambdaQueryWrapper<PayChannelParam>().eq(PayChannelParam::getAppPlatformChannelId, appPlatformChannelId));//根据app应用appid和平台服务类型关系的id查询支付渠道参数列表

            //将payChannelParamDTOS转成json串存入redis
            List<PayChannelParamDTO> payChannelParamDTOList = PayChannelParamConvert.INSTANCE.listentity2listdto(payChannelParamList);
            cache.set(redisKey, JSON.toJSONString(payChannelParamDTOList));//将支付渠道参数保存到redis缓存
        }
    }
}
